#include <nice2d/application.h>
#include <nice2d/bitmask.h>
#include <nice2d/widgets/desktop.h>
#include <nice2d/widgets/control.h>

class ControlData
{
public:
    std::weak_ptr<Control> parent;
    bool active = true;
    bool focus = false;
    float padding = 3.0f;

    ControlResizeRule hResizeRule = ControlResizeRule_Fixed;
    ControlResizeRule vResizeRule = ControlResizeRule_Fixed;

    ControlStylePointer style;
    Bitmask updateBitMask;
};

IMPLEMENT_OBJECT(Control, Entity)

Control::Control(const sf::Vector2f &size):
    Entity(size),
    data(new ControlData())
{
    data->style = std::make_shared<ControlStyle>();

    auto desktop = GET_APPLICATION_COMPONENT(Desktop);
    auto style = desktop->getControlStyle("Control");

    setControlStyle(style);
}

Control::~Control()
{
}

void Control::setPadding(float padding)
{
    if (data->padding != padding) {
        data->padding = padding;
        onPaddingChanged();
    }
}

bool Control::getPadding() const
{
    return data->padding;
}

void Control::setWidth(float width)
{
    if (width > 0) {
        setSize(width, getSize().y);
        caculateSize();
    }
}

float Control::getWidth() const
{
    return getSize().x;
}

void Control::setHeight(float height)
{
    if (height > 0) {
        setSize(getSize().x, height);
        caculateSize();
    }
}

float Control::getHeight() const
{
    return getSize().y;
}

void Control::setParent(std::weak_ptr<Control> parent)
{
    data->parent = parent;
}

std::weak_ptr<Control> Control::getParent() const
{
    return data->parent;
}

void Control::setHResizeRule(ControlResizeRule rule)
{
    if (data->hResizeRule != rule) {
        data->hResizeRule = rule;
        resizeRuleChanged(rule, data->vResizeRule);
    }
}

void Control::setVResizeRule(ControlResizeRule rule)
{
    if (data->vResizeRule != rule) {
        data->vResizeRule = rule;
        resizeRuleChanged(data->hResizeRule, rule);
    }
}

void Control::setResizeRule(ControlResizeRule h, ControlResizeRule v)
{
    setHResizeRule(h);
    setVResizeRule(v);
}

ControlResizeRule Control::getHResizeRule() const
{
    return data->hResizeRule;
}

ControlResizeRule Control::getVResizeRule() const
{
    return data->vResizeRule;
}

void Control::setActive(bool active)
{
    if (isActive() == active)
        return;
    data->active = active;
    activeChanged(active);
    onActiveChanged();
}

bool Control::isActive() const
{
    return data->active;
}

void Control::show()
{
    if (isVisible())
        return;
    setVisible(true);
}

void Control::hide()
{
    if (!isVisible())
        return;
    setVisible(false);
}

void Control::setFocused(bool focus)
{
    if (isFocused() == focus)
        return;

    data->focus = focus;
    focusChanged(focus);
    if (focus)
        onGainFocus();
    else
        onLostFocus();
}

bool Control::isFocused() const
{
    return data->focus;
}

ControlPointer Control::getControlBelow(const sf::Vector2i &point)
{
    return nullptr;
}

bool Control::doesHierarchyContain(ControlPointer other) const
{
    return this == other.get();
}

void Control::caculateSize()
{
}

void Control::setControlStyle(ControlStylePointer style)
{
    if (style) {
        data->style = style;
        data->updateBitMask.setBit(ControlUpdateFlag_Style, true);
    }
}

ControlStylePointer Control::getControlStyle() const
{
    return data->style;
}

void Control::onPaddingChanged()
{
}

void Control::onActiveChanged()
{
    if (isActive() && data->style->normalBackground)
        setBackground(data->style->normalBackground);
    else if (!isActive() && data->style->disableBackground)
        setBackground(data->style->disableBackground);
}

void Control::onGainFocus()
{
}

void Control::onLostFocus()
{
}

void Control::onMouseEnter()
{
    if (isActive() && data->style->hoverBackground)
        setBackground(data->style->hoverBackground);
}

void Control::onMouseExit()
{
    if (isActive() && data->style->normalBackground)
        setBackground(data->style->normalBackground);
}

void Control::onPositionChanged()
{
}

void Control::onSizeChanged()
{
}

void Control::onStyleChanged()
{
    auto style = getControlStyle();

    if (isActive())
        setBackground(style->normalBackground);
    else
        setBackground(style->disableBackground);
}

void Control::onUpdateEntity(float deltaTime)
{
    onUpdateControl(deltaTime);

    if (data->updateBitMask.contain(ControlUpdateFlag_Style)) {
        data->updateBitMask.setBit(ControlUpdateFlag_Style, false);
        onStyleChanged();
    }
}

void Control::onDrawEntity(sf::RenderTarget &target, sf::RenderStates states) const
{
    onDrawControl(target, states);
}

void Control::onUpdateControl(float deltaTime)
{
}

void Control::onDrawControl(sf::RenderTarget &target, sf::RenderStates states) const
{
}










